home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 435_01 / vesatest.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  56.0 KB  |  2,141 lines

  1. // Compiled with Borland C++ v3.1, in Huge memory model and 386 mode.
  2. // Source code by Jason Hughes aka The Panther!
  3. // Plenty of source code taken from Game Programmer's Encyclopedia and other
  4. // public sources.  See readme file for details.
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <dos.h>
  9. #include <conio.h>
  10. #include <alloc.h>
  11. //====Fire routine defines====
  12. #define firewidth 100
  13. #define fireheight 90  // if firewidth*fireheight>65500, this will crash.
  14. //
  15. //==================Sound Blaster Prototypes=================================
  16. //
  17. int  sb_read(void);
  18. void sb_write(char letr);
  19. int  sb_reset(void);
  20. int  sb_detect(void);
  21. void initdma(char far *buffer,int length,int rate);
  22. void closedma(void);
  23. void interrupt sbtesthandler1(...);
  24. void interrupt sbtesthandler2(...);
  25. void interrupt sbtesthandler3(...);
  26. void interrupt sbtesthandler4(...);
  27. //
  28. //==================Mouse-Related Prototypes=================================
  29. //
  30. int setupmouse(void);
  31. void updatecursor(void);
  32. void closemouse(void);
  33. void mousecursor_on(void);
  34. void mousecursor_off(void);
  35. void set_mousecursor(char *picture);
  36. void set_mousewindow(int x1,int y1,int x2,int y2);
  37. //
  38. //==================Miscellaneous Computer Prototypes========================
  39. //
  40. unsigned int Checktimer(void);
  41. char Check386(void);
  42. //
  43. //==================Graphics Internals Prototypes============================
  44. //
  45. void waitretrace(void);
  46. void switchbank(unsigned int newbank);
  47. void clearscr(void);
  48. void setvisualstart(int x,int y);
  49. void fadeoutpalette(unsigned int speed);
  50. void fadeinpalette(char far *inpalt,unsigned int speed);
  51. void setpalette(char far *paloffset);
  52. void getpalette(char far *paloffset);
  53. int  InitVesa(void);
  54. void settextmode(void);
  55. void setcolor(char red, char green, char blue, int color);
  56. void setstandardpalette(int mult,int red,int green,int blue);
  57. //
  58. //==================Graphics I/O Prototypes==================================
  59. //
  60. char *getimage(int x, int y, int width, int height);
  61. void putimage(int x, int y, char *inptr);
  62. void clrimage(int x, int y, int width, int height);
  63. void holedimage(int x, int y, char *inptr);
  64. void orimage(int x, int y, char *inptr);
  65. void xorimage(int x, int y, char *inptr);
  66. unsigned char far *putpixel(unsigned int x,unsigned int y,unsigned char color);
  67. unsigned char getpixel(unsigned int x,unsigned int y);
  68. //
  69. //===========================================================================
  70. //
  71. struct PARAMETERS {
  72.        unsigned char V[4];
  73.        unsigned int version,oem_ofs,oem_seg;
  74.        unsigned long capabilities;
  75.        unsigned int modes_ofs,modes_seg,mem64blocks;
  76.        char wasted[242];
  77.        } parm;
  78.  
  79. struct BLOCK {
  80.        unsigned int vesainfo;
  81.        unsigned char winaatts,winbatts;
  82.        unsigned int grain,size,aseg,bseg;
  83.        void far *bankfunc;
  84.        unsigned int bytesperrow,xres,yres;
  85.        unsigned char xchars,ychars,bitplanes,bppixel,numbanks,memmodel,
  86.                      banksize,planes,reserved,redmask,redpos,greenmask,
  87.                      greenpos,bluemask,bluepos,rsvdmask,rsvdpos,dcinfo;
  88.        char wasted[216];
  89.        } block;
  90.  
  91. int currentbank = 0,bankgrain = 0,bankmask = 0,writeable = 0;
  92. long totalram = 0;  // This contains the amount of ram on the card in K.
  93. unsigned int vidseg = 0xA000,mousetest = 0;
  94. char *mousecursor = NULL;
  95. union REGS regs;
  96. struct SREGS sregs;
  97. int SBInt = 0x200,SBDMA = 0,DMAChannel = 1,Page[4] = {0, 0x83, 0, 0x82 };
  98. int currentbuffer = 0,nextbuffer = 0;
  99. unsigned char oldint21; // DO NOT MODIFY THIS! It's the hardware IRQ mask.
  100. void interrupt (*oldmousehandler1)(...) = NULL,
  101.                (*oldmousehandler2)(...),
  102.                (*oldmousehandler3)(...);
  103. void interrupt (*oldsbhandler1)(...) = NULL,
  104.                (*oldsbhandler2)(...),
  105.                (*oldsbhandler3)(...),
  106.                (*oldsbhandler4)(...);
  107. char *dmabuf,*buffer[2];
  108. int volatile bufflen[2],rate[2];
  109. int omousex,omousey,mousewindow_x1,mousewindow_x2,
  110.     mousewindow_y1,mousewindow_y2,mouseport;
  111. int volatile mousex,mousey;
  112. unsigned char mousecnt = 0,mousemoved = 0,byte1,byte2,byte3,byte4,byte5,
  113.               cursor_on = 0,mousespeed = 255,mousebuttons = 2;
  114. unsigned char volatile mouseb1 = 0,mouseb2 = 0,mouseb3 = 0;
  115. int volatile sbplaying = 0;        // if 0 then not playing anything
  116. unsigned char pal[1536],bankrotator = 0;
  117.  
  118. void setcolor(char red, char green, char blue, int color)
  119. {
  120.  color = (color<<1) + color; // make tmp=color*3
  121.  pal[color++]=red;
  122.  pal[color++]=green;
  123.  pal[color]=blue;
  124. }
  125.  
  126. void waitretrace(void)
  127. {
  128. asm {
  129.     mov dx,0x3DA
  130.     mov ah,8
  131.     }
  132. l1:
  133. asm {
  134.     in   al,dx
  135.     test al,ah   // TEST is 1 clock cycle, whereas AND is 2 on a 386.
  136.     jnz   l1
  137.     }
  138. l2:
  139. asm {
  140.     in   al,dx
  141.     test al,ah
  142.     jz   l2
  143.     }
  144. }
  145.  
  146. char Check386(void)
  147. {                               // returns a 0 for anything less than 386 cpu
  148. asm {
  149.     mov  al,0            // Default to 8086/8088 processor
  150.     push sp
  151.     pop  bx              // BX holds the value of SP or SP-2
  152.     cmp  bx,sp           // 88/86/186 pushes the value of SP-2
  153.     jne  done            // Must be a 286/386/486 type processor
  154.                          // First check for 386/486 in 32 bit mode
  155.     pushf                // Test for 16 or 32 operand size:
  156.     mov  bx,sp           //  pushed 2 or 4 bytes of flags
  157.     popf
  158.     inc  bx
  159.     inc  bx
  160.     cmp  bx,sp           // did pushf change sp by 2?
  161.     jnz  is386           // 32 bit push, so it is a 386/486
  162.  
  163.     sub  sp,6            // Is it a 286/386/486 in 16 bit mode?
  164.     mov  bp,sp
  165.     sgdt [QWORD ptr bp]  // 80286/386/486 specific instrucion
  166.     add  sp,4            // Get global descriptor table
  167.     pop  bx
  168.     inc  bh              // Third word of GDT = -1 for 286
  169.     jz   done
  170.     }
  171. is386:
  172. asm mov  al,1           // 386 or better, not important what.
  173. done:
  174. asm {
  175.     pop ds
  176.     pop bp
  177.     ret
  178.     }
  179.  return(0);     // dummy line, never gets executed.  Suppresses a warning.
  180. }
  181.  
  182. unsigned int Checktimer(void)
  183. {  // It is important to note that sometimes these values come back
  184.    // somewhat off.  It's either this value or some other value, but always
  185.    // repeatably one of two values.  Cannot explain why, but I think it has
  186.    // something to do with being in v86 mode instead of real mode, or some
  187.    // technical crap like that.  <shrug>  I didn't invent this code, so don't
  188.    // scream at me... I just plagarized it like everybody else.
  189. // 486DX2/66MHz  0126h
  190. // 486DX/50MHz   0188h
  191. // 486DX/33MHz   024Ch
  192. // 486SX/20MHz   03D4h
  193. // 386DX/40MHz   04C8h
  194. // 386DX/40MHz   05EDh
  195. // 386DX/33MHz   0733h
  196. // 386DX/16MHz   0DBAh
  197. // 286  /10MHz   1500h
  198. // 086  /4.77MHz 6006h
  199. asm {
  200.     cli
  201.     mov     al, 34h
  202.     out     43h, al         //OUT can be used as immediate
  203.     xor     al, al
  204.     out     40h, al
  205.     out     40h, al
  206.     sti
  207.     mov     cx, 1000h       //action here,
  208.     }
  209. here:
  210. asm {                       //must not take
  211.     dec     cx              //more than 1/18
  212.     jnz     here            //(0.0555) seconds to run
  213.     cli
  214.     mov     al, 4h
  215.     out     43h, al
  216.     in      al, 40h
  217.     mov     dl, al
  218.     in      al, 40h
  219.     mov     dh, al
  220.     sti
  221.     neg     dx              //Action took bx/1193180 seconds
  222.     mov     ax,dx
  223.     pop ds
  224.     pop bp
  225.     ret
  226.     }
  227.  return(0);     // dummy line, never gets executed
  228. }
  229.  
  230. void setpalette(char far *paloffset)
  231. {
  232. asm {
  233.     mov cx,768
  234.     lds bx,dword ptr paloffset
  235.     mov si,bx
  236.     xor ax,ax
  237.     mov dx,0x03C8
  238.     out dx,al
  239.     inc dx
  240.     rep outsb
  241.     }
  242. }
  243.  
  244. void getpalette(char far *paloffset)
  245. {
  246. asm {
  247.     mov cx,768
  248.     les bx,dword ptr paloffset
  249.     mov di,bx
  250.     xor ax,ax
  251.     mov dx,0x03C7
  252.     out dx,al
  253.     add dx,2
  254.     rep insb
  255.     }
  256. }
  257.  
  258. void fadeoutpalette(unsigned int speed)
  259. {
  260.  char counter;
  261.  char palet[2304]; //0-767 cur palette, 768-1535 palstep,
  262.                    //1536-2303 palstep2
  263.  char far *palt;
  264.  
  265.  palt=(char *) MK_FP(FP_SEG(&palet),FP_OFF(&palet));
  266. asm {
  267.     mov cx,768
  268.     les di,dword ptr palt
  269.     xor ax,ax
  270.     mov dx,0x03C7
  271.     out dx,al
  272.     add dx,2
  273.     rep insb         // this has just read in the palette into current pal
  274.     lds si,dword ptr palt
  275.     mov cx,192
  276.     }
  277. shiftpal:
  278. asm {
  279.     lodsd
  280.     shl eax,2
  281.     stosd
  282.     dec cx
  283.     jnz shiftpal     // this just set palstep to be pal * 4
  284.     mov cx,192
  285.     xor eax,eax      // clear palstep2
  286.     rep stosd        // calcforfade finished here
  287.     mov byte ptr counter,64
  288.     }
  289. dropvalues:
  290. asm {
  291.     mov cx,768
  292.     sub si,cx        // reset to start of pal
  293.     }
  294. looppoint:
  295. asm {
  296.     mov ah,[si+768]
  297.     add byte ptr [si+1536],ah
  298.     jnc nodec
  299.     cmp byte ptr [si],0
  300.     je  nodec
  301.     dec byte ptr [si]
  302.     }
  303. nodec:
  304. asm {
  305.     inc si
  306.     dec cx
  307.     jnz looppoint
  308.     mov cx,768
  309.     sub si,cx                 // reposition to start of palt
  310.     mov dx,0x03DA
  311.     }
  312. vrt:
  313. asm {
  314.     in  al,dx
  315.     and al,8
  316.     jz  vrt                   // synch to vertical retrace
  317.     mov dx,0x03C8
  318.     xor al,al
  319.     out dx,al
  320.     inc dx
  321.     rep outsb
  322.     mov cx,word ptr speed
  323.     }
  324. itself:
  325. asm {
  326.     imul ax,ax
  327.     imul ax,ax   // waste time
  328.     dec cx
  329.     jnz itself
  330.     dec byte ptr counter
  331.     jnz dropvalues
  332.     pop ds
  333.     pop di
  334.     pop si
  335.     leave
  336.     ret
  337.     }
  338. }
  339.  
  340. void fadeinpalette(char far *inpalt,unsigned int speed)
  341. {
  342.  char counter;
  343.  char palet[3072]; //0-767 cur palette, 768-1535 palstep,
  344.                    //1536-2303 palstep2, 2304-3071 original pal
  345.  char far *palt;
  346.  
  347.  palt=(char *) MK_FP(FP_SEG(&palet),FP_OFF(&palet));
  348. asm {
  349.     mov cx,768
  350.     les di,dword ptr palt
  351.     xor ax,ax
  352.     mov dx,0x03C7
  353.     out dx,al
  354.     add dx,2
  355.     rep insb         // this has just read in the palette into current pal
  356.     lds si,dword ptr inpalt
  357.     mov cx,192
  358.     }
  359. shiftpal:
  360. asm {
  361.     lodsd
  362.     shl eax,2
  363.     stosd
  364.     dec cx
  365.     jnz shiftpal     // this just set palstep to be inpalt * 4
  366.     mov cx,192
  367.     xor eax,eax
  368.     rep stosd        // clear palstep2
  369.     sub si,768
  370.     mov cx,192
  371.     rep movsd        // copy given palette inpalt to original pal
  372.  
  373.     lds si,dword ptr palt
  374.     add si,768
  375.     mov byte ptr counter,64
  376.     }
  377. dropvalues:
  378. asm {
  379.     mov cx,768
  380.     sub si,cx        // reset to start of pal
  381.     }
  382. looppoint:
  383. asm {
  384.     mov ah,[si+768]
  385.     add byte ptr [si+1536],ah
  386.     jnc noinc
  387.     mov ah,byte ptr [si+2304]   // get original pal color
  388.     cmp byte ptr [si],ah
  389.     je  noinc
  390.     inc byte ptr [si]
  391.     }
  392. noinc:
  393. asm {
  394.     inc si
  395.     dec cx
  396.     jnz looppoint
  397.     mov cx,768
  398.     sub si,cx                 // reposition to start of palt
  399.     mov dx,0x03DA
  400.     }
  401. vrt:
  402. asm {
  403.     in  al,dx
  404.     and al,8
  405.     jz  vrt                   // synch to vertical retrace
  406.     mov dx,0x03C8
  407.     xor al,al
  408.     out dx,al
  409.     inc dx
  410.     rep outsb
  411.     mov cx,word ptr speed
  412.     }
  413. itself:
  414. asm {
  415.     imul ax,ax
  416.     imul ax,ax   // waste time
  417.     dec cx
  418.     jnz itself
  419.     dec byte ptr counter
  420.     jnz dropvalues
  421.     pop ds
  422.     pop di
  423.     pop si
  424.     leave
  425.     ret
  426.     }
  427. }
  428.  
  429. void setstandardpalette(int mult,int red,int green,int blue)
  430. {
  431.  char r,g,b;
  432.  int r2,g2,b2;
  433.  
  434.  if(mult>12) mult=12;
  435.  if(mult<0) mult=0;
  436.  for (r=0; r<5; r++)
  437.      for (g=0; g<5; g++)
  438.          for (b=0; b<5; b++) {
  439.              r2=r*mult+red;
  440.              if (r2>63) r2=63;
  441.                 else if (r2<0) r2=0;
  442.              g2=g*mult+green;
  443.              if (g2>63) g2=63;
  444.                 else if (g2<0) g2=0;
  445.              b2=b*mult+blue;
  446.              if (b2>63) b2=63;
  447.                else if (b2<0) b2=0;
  448.              setcolor(r2,g2,b2,r+5*g+25*b);
  449.              }
  450.  for(r2=125; r2<255; r2++) setcolor(0,0,0,r2);
  451.  setcolor(63,63,63,255);
  452.  setpalette(pal);
  453. }
  454.  
  455. int InitVesa(void)
  456. {
  457.  unsigned int far *listptr;
  458.  unsigned readseg,writeseg;
  459.  char readable;
  460.  
  461.  
  462.  sregs.es = FP_SEG(&parm);
  463.  regs.x.di = FP_OFF(&parm);
  464.  regs.x.ax = 0x4F00;
  465.  int86x(0x10,®s,®s,&sregs);
  466.  totalram = (long)parm.mem64blocks*64;
  467.  if (regs.x.ax==0x004F && strncmp("VESA",parm.V,4)==0 && totalram>=1024) {
  468.     for (listptr = (unsigned int *) MK_FP(parm.modes_seg,parm.modes_ofs);
  469.          *listptr != 0xFFFF && *listptr != 0x0101; listptr++);
  470.     if (*listptr == 0xFFFF) {
  471.        settextmode();  // this resets the palette from black and clrs screen
  472.        printf("The 640x480x256 VESA mode was not detected.\n");
  473.        return(0);
  474.        }
  475.     else {
  476.          sregs.es = FP_SEG(&block);
  477.          regs.x.di = FP_OFF(&block);
  478.          regs.x.ax = 0x4F01;
  479.          regs.x.cx = 0x0101;
  480.          int86x(0x10,®s,®s,&sregs);
  481.          if (regs.x.ax==0x004F && (block.vesainfo & 1)==1) {
  482.             writeable = 0;
  483.             writeseg = block.aseg;
  484.             if ((block.winbatts & 5)==5 && (block.winaatts & 4)==0) {
  485.                writeseg = block.bseg;
  486.                writeable = 1;
  487.                }
  488.             readseg = block.aseg;
  489.             readable = 0;
  490.             if ((block.winbatts & 3)==3 && (block.winaatts & 2)==0) {
  491.                readseg = block.bseg;
  492.                readable = 1;
  493.                }
  494.             if (readseg!=writeseg) {
  495.                settextmode();  // this resets the palette from black and clrs screen
  496.                printf("VESA read/write windows do not overlap.  In order for this to work, they must.\n");
  497.                return(0);
  498.                }
  499.             if (readable!=writeable) {
  500.                settextmode();  // this resets the palette from black and clrs screen
  501.                printf("VESA read/write windows are separate.  In order for this to work, they must be.\n");
  502.                return(0);
  503.                }
  504.             vidseg = readseg;
  505.             regs.x.ax = 0x4F02;
  506.             regs.x.bx = 0x0101;
  507.             int86(0x10,®s,®s);
  508.             if (block.size!=64) {
  509.                settextmode();  // this resets the palette from black and clrs screen
  510.                printf("Your video driver/hardware configuration does not supply 64k graphic windows.\n");
  511.                return(0);
  512.                }
  513.            // this next section sets the video for 1024x480x256, for easy calculations
  514.             for (readseg=0; readseg<768; readseg++)
  515.                 pal[readseg]=0;
  516.             setpalette((char far *) pal);
  517.             regs.x.ax = 0x4F06;
  518.             regs.x.bx = 0x0000;
  519.             regs.x.cx = 1024;
  520.             int86(0x10,®s,®s);
  521.             if (regs.x.ax!=0x004F) {
  522.                settextmode();  // this resets the palette from black and clrs screen
  523.                printf("Your video driver MUST supply 1 meg of available ram and virtual paging.\n");
  524.                return(0);
  525.                } //set banks to be on 64-line intervals ONLY!
  526.             bankmask = 64/block.grain;
  527.             bankrotator = 7; // set this up so we don't do it again in put/getpixel
  528.             readseg = bankmask; // put this in granularity units
  529.             bankgrain = 0;
  530.             while (readseg!=0) {
  531.                   bankgrain++; //this is the base unit for banks. add this to currentbank
  532.                   readseg >>= 1;  //in order to set the next 64k bank
  533.                   }
  534.             bankrotator -= bankgrain;
  535.             bankgrain = bankmask;
  536.             bankmask--;
  537.             bankmask = 0xFFFF ^ bankmask;
  538.             clearscr();
  539.             return(1);
  540.             }
  541.          else {
  542.               settextmode();  // this resets the palette from black and clrs screen
  543.               printf("Error in GetModeData() for 640x480x256.\n");
  544.               if ((block.vesainfo & 1)==0)
  545.                  printf("Mode not supported (but was detected)!\n");
  546.               return(0);
  547.               }
  548.          }
  549.  
  550.     }
  551.  else {
  552.       settextmode();  // this resets the palette from black and clrs screen
  553.       if (totalram>=1024) printf("There was an error in the InitVesa() call.\n");
  554.          else printf("This graphics driver requires 1meg or more of ram on your SVGA card.\n");
  555.       return(0);
  556.       }
  557.  
  558. }
  559.  
  560. void settextmode(void)
  561. {
  562.  asm {
  563.      mov ax,0x4F02
  564.      mov bx,0x0003
  565.      int 0x10
  566.      }
  567. }
  568.  
  569. void switchbank(unsigned int newbank)
  570. { // newbank passed in should be (Y >> bankrotator) & bankmask
  571.   // if you want to maintain keeping banks on even 64k boundaries, as I do in
  572.   // all of my routines.  You may not.
  573. asm {
  574.     mov dx,newbank
  575.     mov currentbank,dx
  576.     mov bx,writeable
  577.     call dword ptr block.bankfunc
  578.     }
  579. }
  580.  
  581. unsigned char far *putpixel(unsigned int x,unsigned int y,unsigned char color)
  582. {
  583. asm {
  584.     mov dx,word ptr y
  585.     mov di,dx
  586.     mov cl,byte ptr bankrotator
  587.     shr dx,cl
  588.     and dx,word ptr bankmask
  589.     cmp dx,word ptr currentbank
  590.     je  noswitch
  591.     mov word ptr currentbank,dx
  592.     mov bx,word ptr writeable
  593.     call dword ptr block.bankfunc
  594.     }
  595. noswitch:
  596. asm {
  597.     mov es,word ptr vidseg
  598.     shl di,10
  599.     add di,word ptr x
  600.     mov al,byte ptr color
  601.     stosb
  602.     mov ax,di
  603.     mov dx,es
  604.     dec ax
  605.     pop ds
  606.     pop di
  607.     pop bp
  608.     ret
  609.     }
  610. return((char *)MK_FP(vidseg,0));  // this is a dummy, never gets executed
  611. }
  612.  
  613. unsigned char getpixel(unsigned int x,unsigned int y)
  614. {
  615. asm {
  616.     mov dx,word ptr y
  617.     mov si,dx
  618.     mov cl,byte ptr bankrotator
  619.     shr dx,cl
  620.     and dx,word ptr bankmask
  621.     cmp dx,word ptr currentbank
  622.     je  noswitch
  623.     mov word ptr currentbank,dx
  624.     mov bx,word ptr writeable
  625.     call dword ptr block.bankfunc
  626.     }
  627. noswitch:
  628. asm {
  629.     mov ds,word ptr vidseg
  630.     shl si,10
  631.     add si,word ptr x
  632.     lodsb
  633.     pop ds
  634.     pop si
  635.     pop bp
  636.     ret
  637.     }
  638.  return(*(char *)MK_FP(vidseg,0)); // this is a dummy line, never gets run
  639. }
  640.  
  641. void setvisualstart(int x,int y)
  642. {
  643.  asm {
  644.      mov ax,0x4F07
  645.      mov bx,0
  646.      mov cx,x
  647.      mov dx,y
  648.      int 0x10
  649.      }
  650. }
  651.  
  652. void clearscr(void)  // clears all video memory, not just the visible screen
  653. {                     // takes into account more than 1 meg cards too.
  654.  int loop,loop2;
  655.  long far *start;
  656.  
  657.  for (loop2=0; loop2<totalram; loop2++) {
  658.      start = (long far *) putpixel(0,loop2,0);
  659.      for (loop=0; loop<256; loop++)
  660.          *(start++) = 0; // write longs only, in case it's a 32 bit bus
  661.      }
  662. }
  663.  
  664. char *getimage(int x, int y, int width, int height)
  665. {  // this is _NOT_ well optimized, but I don't care.  I suggest that this
  666.    // not be used in timing critical routines/programs, ie. games.
  667.  unsigned int newbank;
  668.  long far *pixel;
  669.  long *picture;
  670.  char *temppic;
  671.  int tmpx,stopy,loopx,addtopixel,endofbank;
  672.  
  673.  tmpx = width >> 2;
  674.  stopy = y+height;
  675.  picture = (long *) (temppic = (char *) malloc(width*height));
  676.  if (picture==NULL) {
  677.     settextmode();
  678.     printf("Memory allocation error.  Tried to allocate %u bytes.\n",width*height);
  679.     printf("Max available memory is %lu.\n",(unsigned long) coreleft());
  680.     printf("Max available far memory is %lu.\n",(unsigned long) farcoreleft());
  681.     exit(1);
  682.     }
  683.  *((int *)((int *)picture)++) = width;
  684.  *((int *)((int *)picture)++) = height;
  685.  addtopixel = 1024-width;
  686.  
  687.  pixel = (long *) MK_FP(vidseg,(y << 10)+x);
  688.  newbank = (y >> bankrotator) & bankmask;
  689.  if (newbank!=currentbank) {
  690.     regs.x.ax = 0x4F05;
  691.     regs.x.bx = writeable;
  692.     regs.x.dx = newbank;
  693.     int86(0x10,®s,®s);
  694.     }
  695.  endofbank = 64-(y & 63);
  696.  switch (width & 3) {
  697.    case 0 : for (; y<stopy; y++) {
  698.                 for (loopx = 0; loopx<tmpx; loopx++)
  699.                     *(picture++) = *(pixel++);
  700.                 (char *) pixel += addtopixel;
  701.                 endofbank--;
  702.                 if (endofbank==0) {
  703.                    newbank += bankgrain;  //select next bank
  704.                    endofbank = 64;
  705.                    regs.x.ax = 0x4F05;
  706.                    regs.x.bx = writeable;
  707.                    regs.x.dx = newbank;
  708.                    int86(0x10,®s,®s);
  709.                    }
  710.                 } break;
  711.    case 1 : for (; y<stopy; y++) {
  712.                 *((char *)((char *)picture)++) = *((char *)((char *)pixel)++);
  713.                 for (loopx = 0; loopx<tmpx; loopx++)
  714.                     *(picture++) = *(pixel++);
  715.                 (char *) pixel += addtopixel;
  716.                 endofbank--;
  717.                 if (endofbank==0) {
  718.                    newbank += bankgrain;  //select next bank
  719.                    endofbank = 64;
  720.                    regs.x.ax = 0x4F05;
  721.                    regs.x.bx = writeable;
  722.                    regs.x.dx = newbank;
  723.                    int86(0x10,®s,®s);
  724.                    }
  725.                 } break;
  726.    case 2 : for (; y<stopy; y++) {
  727.                 *((unsigned *)((unsigned *)picture)++) = *((unsigned *)((unsigned *)pixel)++);
  728.                 for (loopx = 0; loopx<tmpx; loopx++)
  729.                     *(picture++) = *(pixel++);
  730.                 (char *) pixel += addtopixel;
  731.                 endofbank--;
  732.                 if (endofbank==0) {
  733.                    newbank += bankgrain;  //select next bank
  734.                    endofbank = 64;
  735.                    regs.x.ax = 0x4F05;
  736.                    regs.x.bx = writeable;
  737.                    regs.x.dx = newbank;
  738.                    int86(0x10,®s,®s);
  739.                    }
  740.                 } break;
  741.    case 3 : for (; y<stopy; y++) {
  742.                 *((unsigned *)((unsigned *)picture)++) = *((unsigned *)((unsigned *)pixel)++);
  743.                 *((char *)((char *)picture)++) = *((char *)((char *)pixel)++);
  744.                 for (loopx = 0; loopx<tmpx; loopx++)
  745.                     *(picture++) = *(pixel++);
  746.                 (char *) pixel += addtopixel;
  747.                 endofbank--;
  748.                 if (endofbank==0) {
  749.                    newbank += bankgrain;  //select next bank
  750.                    endofbank = 64;
  751.                    regs.x.ax = 0x4F05;
  752.                    regs.x.bx = writeable;
  753.                    regs.x.dx = newbank;
  754.                    int86(0x10,®s,®s);
  755.                    }
  756.                 }
  757.      }
  758.  currentbank = newbank;
  759.  return(temppic);
  760. }
  761.  
  762. void putimage(int x, int y, char *inptr)
  763. {
  764. asm {
  765.     jmp entryput
  766.  newbank       dw ?   // these are used by the putimage routine
  767.  startnext     dw ?
  768.  tempds        dw ?
  769.  tempbankgrain dw ?
  770.  tempbankfunc  dd ?
  771.  tempwriteable dw ?
  772.  tempwidth     dw ?
  773.  }
  774. entryput:
  775. asm {
  776.     mov ax,writeable
  777.     mov tempwriteable,ax
  778.     mov ax,bankgrain
  779.     mov tempbankgrain,ax
  780.     mov eax,dword ptr block.bankfunc
  781.     mov tempbankfunc,eax
  782.     mov tempds,ds
  783.     mov dx,y
  784.     mov di,dx        //di = Y
  785.     mov cl,bankrotator
  786.     shr dx,cl
  787.     and dx,bankmask
  788.     mov newbank,dx
  789.     cmp dx,currentbank
  790.     je  nobank
  791.  
  792.     mov bx,writeable
  793.     call dword ptr tempbankfunc  //switch to a new bank if necessary
  794.     }                              // dx=newbank
  795. nobank:
  796.  asm {
  797.      mov ax,di
  798.      mov bh,64
  799.      and al,63
  800.      sub bh,al        // set up endofbank counter in bh
  801.  
  802.      mov ax,di        // ax = Y
  803.      mov es,vidseg
  804.      shl ax,10
  805.      add ax,x         // figure out the *pixel address in es:di
  806.      mov di,ax
  807.  
  808.      mov ax,[inptr]   // how does lds work?
  809.      mov si,ax
  810.      mov ax,[inptr+2]
  811.      mov ds,ax
  812.      lodsw
  813.      mov tempwidth,ax // this is temporary storage for the width of the pic
  814.      mov dx,1024
  815.      sub dx,ax
  816.      mov startnext,dx // dx will be addtopixel from here on out
  817.      lodsw            // counter will be in ax from here on out
  818.      }
  819. looppoint1:           // until count (in fs) = 0
  820.  asm {
  821.      mov cx,tempwidth // put width in cx
  822.  
  823.      shr cx,1
  824.      jnc notone
  825.      movsb
  826.      }
  827. notone:
  828.  asm {
  829.      shr cx,1
  830.      jnc nottwo
  831.      movsw
  832.      }
  833. nottwo:
  834.  asm {
  835.      jcxz not128
  836.      rep movsd
  837.      }
  838. not128:
  839.  asm {
  840.      dec ax
  841.      je endit
  842.  
  843.      add di,dx           // set for next line starting point
  844.      dec bh              // when bh (endofbank) is 0, switch banks
  845.      jne looppoint1
  846.      }
  847. changebank:
  848.  asm {
  849.      mov dx,newbank
  850.      add dx,tempbankgrain    // select next bank
  851.      mov newbank,dx
  852.      mov bx,tempwriteable
  853.      mov cx,ax
  854.      call dword ptr tempbankfunc  //destroys dx and ax
  855.      mov ax,cx
  856.      mov dx,startnext
  857.      mov bh,64           // set next endofbank to be 64 lines
  858.      test ax,0xFF
  859.      jnz looppoint1
  860.      }
  861. endit:
  862.  asm {
  863.      mov ax,tempds
  864.      mov ds,ax
  865.      mov ax,newbank
  866.      mov currentbank,ax
  867.      }
  868. }
  869.  
  870. void xorimage(int x, int y, char *inptr)
  871. {
  872. asm {
  873.     jmp entryxor
  874.  xnewbank       dw ?   // these are used by the xorimage routine
  875.  xstartnext     dw ?
  876.  xtempds        dw ?
  877.  xtempbankgrain dw ?
  878.  xtempbankfunc  dd ?
  879.  xtempwriteable dw ?
  880.  xtempwidth     dw ?
  881.  }
  882. entryxor:
  883. asm {
  884.     mov ax,writeable
  885.     mov xtempwriteable,ax
  886.     mov ax,bankgrain
  887.     mov xtempbankgrain,ax
  888.     mov eax,dword ptr block.bankfunc
  889.     mov xtempbankfunc,eax
  890.     mov xtempds,ds
  891.     mov dx,y
  892.     mov di,dx        //di = Y
  893.     mov cl,bankrotator
  894.     shr dx,cl
  895.     and dx,bankmask
  896.     mov xnewbank,dx
  897.     cmp dx,currentbank
  898.     je  nobank
  899.  
  900.     mov bx,xtempwriteable
  901.     call dword ptr xtempbankfunc  //switch to a new bank if necessary
  902.     }                              // dx=newbank
  903. nobank:
  904.  asm {
  905.      mov ax,di
  906.      mov bh,64
  907.      and al,63
  908.      sub bh,al        // set up endofbank counter in bh
  909.  
  910.      mov ax,di        // ax = Y
  911.      mov es,vidseg
  912.      shl ax,10
  913.      add ax,x         // figure out the *pixel address in es:di
  914.      mov di,ax
  915.  
  916.      mov ax,[inptr]   // how does lds work?
  917.      mov si,ax
  918.      mov ax,[inptr+2]
  919.      mov ds,ax
  920.      lodsw
  921.      mov xtempwidth,ax // this is temporary storage for the width of the pic
  922.      mov dx,1024
  923.      sub dx,ax
  924.      mov xstartnext,dx
  925.      lodsw            // counter will be in ax from here on out
  926.      }
  927. looppoint1:           // until count (in fs) = 0
  928.  asm {
  929.      mov cx,xtempwidth // put width in cx
  930.  
  931.      shr cx,1
  932.      jnc looptwo
  933.      mov dl,[si]
  934.      xor es:[di],dl
  935.      inc di
  936.      inc si
  937.      }
  938. looptwo:
  939.  asm {
  940.      shr cx,1
  941.      jnc looppoint2
  942.      mov dx,word ptr [si]
  943.      xor word ptr es:[di],dx
  944.      add di,2
  945.      add si,2
  946.      }
  947. looppoint2:
  948.  asm {
  949.      mov edx,dword ptr [si]
  950.      xor dword ptr es:[di],edx
  951.      add di,4
  952.      add si,4
  953.      dec cx
  954.      jnz looppoint2
  955.      }
  956. not128:
  957.  asm {
  958.      dec ax
  959.      je endit
  960.  
  961.      add di,xstartnext    // set for next line starting point
  962.      dec bh              // when bh (endofbank) is 0, switch banks
  963.      jne looppoint1
  964.      }
  965. changebank:
  966.  asm {
  967.      mov dx,xnewbank
  968.      add dx,xtempbankgrain    // select next bank
  969.      mov xnewbank,dx
  970.      mov bx,xtempwriteable
  971.      mov cx,ax
  972.      call dword ptr xtempbankfunc  //destroys dx and ax
  973.      mov ax,cx
  974.      mov bh,64           // set next endofbank to be 64 lines
  975.      test ax,0xFF
  976.      jnz looppoint1
  977.      }
  978. endit:
  979.  asm {
  980.      mov ax,xtempds
  981.      mov ds,ax
  982.      mov ax,xnewbank
  983.      mov currentbank,ax
  984.      }
  985. }
  986.  
  987. void orimage(int x, int y, char *inptr)
  988. {
  989. asm {
  990.     jmp entryxor
  991.  onewbank       dw ?   // these are used by the orimage routine
  992.  ostartnext     dw ?
  993.  otempds        dw ?
  994.  otempbankgrain dw ?
  995.  otempbankfunc  dd ?
  996.  otempwriteable dw ?
  997.  otempwidth     dw ?
  998.  }
  999. entryxor:
  1000. asm {
  1001.     mov ax,writeable
  1002.     mov otempwriteable,ax
  1003.     mov ax,bankgrain
  1004.     mov otempbankgrain,ax
  1005.     mov eax,dword ptr block.bankfunc
  1006.     mov otempbankfunc,eax
  1007.     mov otempds,ds
  1008.     mov dx,y
  1009.     mov di,dx        //di = Y
  1010.     mov cl,bankrotator
  1011.     shr dx,cl
  1012.     and dx,bankmask
  1013.     mov onewbank,dx
  1014.     cmp dx,currentbank
  1015.     je  nobank
  1016.  
  1017.     mov bx,otempwriteable
  1018.     call dword ptr otempbankfunc  //switch to a new bank if necessary
  1019.     }                              // dx=newbank
  1020. nobank:
  1021.  asm {
  1022.      mov ax,di
  1023.      mov bh,64
  1024.      and al,63
  1025.      sub bh,al        // set up endofbank counter in bh
  1026.  
  1027.      mov ax,di        // ax = Y
  1028.      mov es,vidseg
  1029.      shl ax,10
  1030.      add ax,x         // figure out the *pixel address in es:di
  1031.      mov di,ax
  1032.  
  1033.      mov ax,[inptr]   // how does lds work?
  1034.      mov si,ax
  1035.      mov ax,[inptr+2]
  1036.      mov ds,ax
  1037.      lodsw
  1038.      mov otempwidth,ax // this is temporary storage for the width of the pic
  1039.      mov dx,1024
  1040.      sub dx,ax
  1041.      mov ostartnext,dx
  1042.      lodsw            // counter will be in ax from here on out
  1043.      }
  1044. looppoint1:           // until count (in fs) = 0
  1045.  asm {
  1046.      mov cx,otempwidth // put width in cx
  1047.  
  1048.      shr cx,1
  1049.      jnc looptwo
  1050.      mov dl,[si]
  1051.      or es:[di],dl
  1052.      inc di
  1053.      inc si
  1054.      }
  1055. looptwo:
  1056.  asm {
  1057.      shr cx,1
  1058.      jnc looppoint2
  1059.      mov dx,word ptr [si]
  1060.      or word ptr es:[di],dx
  1061.      add di,2
  1062.      add si,2
  1063.      }
  1064. looppoint2:
  1065.  asm {
  1066.      mov edx,dword ptr [si]
  1067.      or dword ptr es:[di],edx
  1068.      add di,4
  1069.      add si,4
  1070.      dec cx
  1071.      jnz looppoint2
  1072.      }
  1073. not128:
  1074.  asm {
  1075.      dec ax
  1076.      je endit
  1077.  
  1078.      add di,ostartnext    // set for next line starting point
  1079.      dec bh              // when bh (endofbank) is 0, switch banks
  1080.      jne looppoint1
  1081.      }
  1082. changebank:
  1083.  asm {
  1084.      mov dx,onewbank
  1085.      add dx,otempbankgrain    // select next bank
  1086.      mov onewbank,dx
  1087.      mov bx,otempwriteable
  1088.      mov cx,ax
  1089.      call dword ptr otempbankfunc  //destroys dx and ax
  1090.      mov ax,cx
  1091.      mov bh,64           // set next endofbank to be 64 lines
  1092.      test ax,0xFF
  1093.      jnz looppoint1
  1094.      }
  1095. endit:
  1096.  asm {
  1097.      mov ax,otempds
  1098.      mov ds,ax
  1099.      mov ax,onewbank
  1100.      mov currentbank,ax
  1101.      }
  1102. }
  1103.  
  1104. void holedimage(int x, int y, char *inptr)
  1105. {  // zero color is a transparent pixel here
  1106. asm {
  1107.     jmp entryxor
  1108.  hnewbank       dw ?   // these are used by the holedimage routine
  1109.  hstartnext     dw ?
  1110.  htempds        dw ?
  1111.  htempbankgrain dw ?
  1112.  htempbankfunc  dd ?
  1113.  htempwriteable dw ?
  1114.  htempwidth     dw ?
  1115.  }
  1116. entryxor:
  1117. asm {
  1118.     mov ax,writeable
  1119.     mov htempwriteable,ax
  1120.     mov ax,bankgrain
  1121.     mov htempbankgrain,ax
  1122.     mov eax,dword ptr block.bankfunc
  1123.     mov htempbankfunc,eax
  1124.     mov htempds,ds
  1125.     mov dx,y
  1126.     mov di,dx        //di = Y
  1127.     mov cl,bankrotator
  1128.     shr dx,cl
  1129.     and dx,bankmask
  1130.     mov hnewbank,dx
  1131.     cmp dx,currentbank
  1132.     je  nobank
  1133.  
  1134.     mov bx,htempwriteable
  1135.     call dword ptr htempbankfunc  //switch to a new bank if necessary
  1136.     }                              // dx=newbank
  1137. nobank:
  1138.  asm {
  1139.      mov ax,di
  1140.      mov bh,64
  1141.      and al,63
  1142.      sub bh,al        // set up endofbank counter in bh
  1143.  
  1144.      mov ax,di        // ax = Y
  1145.      mov es,vidseg
  1146.      shl ax,10
  1147.      add ax,x         // figure out the *pixel address in es:di
  1148.      mov di,ax
  1149.  
  1150.      mov ax,[inptr]   // how does lds work?
  1151.      mov si,ax
  1152.      mov ax,[inptr+2]
  1153.      mov ds,ax
  1154.      lodsw
  1155.      mov htempwidth,ax // this is temporary storage for the width of the pic
  1156.      mov dx,1024
  1157.      sub dx,ax
  1158.      mov hstartnext,dx
  1159.      lodsw            // counter will be in ax from here on out
  1160.      }
  1161. looppoint1:           // until count (in fs) = 0
  1162.  asm {
  1163.      mov cx,htempwidth // put width in cx
  1164.      mov bl,0xFF         // used for FAST test instruction, register-register
  1165.      }
  1166. looppoint2:
  1167.  asm {
  1168.      shr cx,1
  1169.      jnc dotwos
  1170.      mov dl,[si]
  1171.      test dl,bl
  1172.      jz  noplot1
  1173.      mov es:[di],dl
  1174.      }
  1175. noplot1:
  1176.  asm {
  1177.      inc di
  1178.      inc si
  1179.      }
  1180. dotwos:
  1181.  asm {
  1182.      mov dx,[si]
  1183.      add si,2
  1184.      cmp dx,0
  1185.      je  addpoint
  1186.      test dl,bl
  1187.      jz  noplot2       // branch if first pixel is not lit
  1188.      test dh,bl
  1189.      jz  noplot3       // branch if first is lit, but not second
  1190.      mov es:[di],dx    // both are lit pixels
  1191.      add di,2
  1192.      dec cx
  1193.      jnz dotwos
  1194.      jz  not128
  1195.      }
  1196. noplot2:
  1197.  asm {
  1198.      inc di
  1199.      mov es:[di],dh
  1200.      inc di
  1201.      dec cx
  1202.      jnz dotwos
  1203.      jz  not128
  1204.      }
  1205. noplot3:
  1206.  asm mov es:[di],dl
  1207. addpoint:
  1208.  asm {
  1209.      add di,2
  1210.      dec cx
  1211.      jnz dotwos
  1212.      }
  1213. not128:
  1214.  asm {
  1215.      dec ax
  1216.      je endit
  1217.  
  1218.      add di,hstartnext   // set for next line starting point
  1219.      dec bh              // when bh (endofbank) is 0, switch banks
  1220.      jne looppoint1
  1221.      }
  1222. changebank:
  1223.  asm {
  1224.      mov dx,hnewbank
  1225.      add dx,htempbankgrain    // select next bank
  1226.      mov hnewbank,dx
  1227.      mov bx,htempwriteable
  1228.      mov cx,ax
  1229.      call dword ptr htempbankfunc  //destroys dx and ax
  1230.      mov ax,cx
  1231.      mov bh,64           // set next endofbank to be 64 lines
  1232.      test ax,0xFF
  1233.      jnz looppoint1
  1234.      }
  1235. endit:
  1236.  asm {
  1237.      mov ax,htempds
  1238.      mov ds,ax
  1239.      mov ax,hnewbank
  1240.      mov currentbank,ax
  1241.      }
  1242. }
  1243.  
  1244. void clrimage(int x, int y, int width, int height)
  1245. {
  1246.  int cnewbank,cstartnext;
  1247.  
  1248. asm {
  1249.     mov dx,y
  1250.     mov di,dx        //di = Y
  1251.     mov cl,bankrotator
  1252.     shr dx,cl
  1253.     and dx,bankmask
  1254.     mov cnewbank,dx
  1255.     cmp dx,currentbank
  1256.     je  nobank
  1257.  
  1258.     mov bx,writeable
  1259.     call dword ptr block.bankfunc  //switch to a new bank if necessary
  1260.     }                              // dx=newbank
  1261. nobank:
  1262.  asm {
  1263.      mov ax,di
  1264.      mov bh,64
  1265.      and al,63
  1266.      sub bh,al        // set up endofbank counter in bh
  1267.  
  1268.      mov ax,di        // ax = Y
  1269.      mov es,vidseg
  1270.      shl ax,10
  1271.      add ax,x         // figure out the *pixel address in es:di
  1272.      mov di,ax
  1273.  
  1274.      mov ax,width
  1275.      mov dx,1024
  1276.      sub dx,ax
  1277.      mov cstartnext,dx
  1278.      }
  1279. looppoint1:           // until count = 0
  1280.  asm {
  1281.      mov cx,width // put width in cx
  1282.  
  1283.      shr cx,1
  1284.      jnc looptwo
  1285.      mov byte ptr es:[di],0
  1286.      inc di
  1287.      }
  1288. looptwo:
  1289.  asm {
  1290.      shr cx,1
  1291.      jnc looppoint2
  1292.      mov word ptr es:[di],0
  1293.      add di,2
  1294.      }
  1295. looppoint2:
  1296.  asm {
  1297.      mov eax,0
  1298.      rep stosd
  1299.      dec word ptr height
  1300.      je endit
  1301.  
  1302.      add di,cstartnext    // set for next line starting point
  1303.      dec bh              // when bh (endofbank) is 0, switch banks
  1304.      jne looppoint1
  1305.      }
  1306. changebank:
  1307.  asm {
  1308.      mov dx,cnewbank
  1309.      add dx,bankgrain    // select next bank
  1310.      mov cnewbank,dx
  1311.      mov bx,writeable
  1312.      call dword ptr block.bankfunc  //destroys dx and ax
  1313.      mov bh,64           // set next endofbank to be 64 lines
  1314.      cmp word ptr height,0
  1315.      jne looppoint1
  1316.      }
  1317. endit:
  1318.  asm {
  1319.      mov ax,cnewbank
  1320.      mov currentbank,ax
  1321.      }
  1322. }
  1323.  
  1324. void interrupt mousehandler(...)
  1325. {
  1326.  switch (mousecnt) {
  1327.    case 0: {
  1328.         byte1=inportb(mouseport);
  1329.         if (((byte1 & 64)==64) || ((byte1 & 248)==128)) //sync mouse interrupt
  1330.            mousecnt++;  //first check is for 2-button, second is for 3-button
  1331.         break;
  1332.         }
  1333.    case 1: {  // this doesn't bother to check syncronization except on the
  1334.               // first byte of a sequence.  That's probably good enough.
  1335.         byte2=inportb(mouseport);
  1336.         mousecnt++;
  1337.         break;
  1338.         }
  1339.    case 2: {
  1340.         byte3=inportb(mouseport);
  1341.         if ((byte1 & 64)==64) {
  1342.            mousecnt = 0;
  1343.            byte4 = byte2+(byte1 << 6);
  1344.            byte5 = byte3+((byte1 & 12) << 4);
  1345.            mousex += (signed char) byte4;
  1346.            mousey += (signed char) byte5;
  1347.            if ((byte4 & 127)>mousespeed) mousex += (signed char) byte4;
  1348.            if ((byte5 & 127)>mousespeed) mousey += (signed char) byte5;
  1349.            mouseb1 = (byte1 & 32) >> 5;
  1350.            mouseb2 = (byte1 & 16) >> 4;
  1351. //    the following line makes left and right buttons simulate a center button
  1352. //  so you can write games for three button mice and not need special crap
  1353. //  for 2-button mice.  They are transparent now!
  1354.            if (mouseb1 && mouseb2) {
  1355.               mouseb3 = 1;
  1356.               mouseb1 = 0;
  1357.               mouseb2 = 0;
  1358.               } // also shuts off buttons 1 and 2 while simulating button 3!
  1359. //           mouseb3 = 0;  //this line makes the center button always off
  1360.            if (mousex>mousewindow_x2) mousex = mousewindow_x2;
  1361.            if (mousex<mousewindow_x1) mousex = mousewindow_x1;
  1362.            if (mousey>mousewindow_y2) mousey = mousewindow_y2;
  1363.            if (mousey<mousewindow_y1) mousey = mousewindow_y1;
  1364.            mousemoved = 1; // this is the program's indicator that it moved
  1365.            }
  1366.         else {
  1367.              mousex += (signed char) byte2;
  1368. // positive direction for Y is up, so reverse the sign
  1369.              mousey -= (signed char) byte3;
  1370.              if ((byte2 & 127)>mousespeed) mousex += (signed char) byte4;
  1371.              if ((byte3 & 127)>mousespeed) mousey -= (signed char) byte5;
  1372. // the info I have on these says 0==pressed, but my tests show the opposite.
  1373. // If the info was right and this code was wrong, please email me!
  1374.              mouseb1 = !((byte1 & 4) >> 2);
  1375.              mouseb2 = !(byte1 & 1);
  1376.              mouseb3 = !((byte1 & 2) >> 1);
  1377.              if (mousex>mousewindow_x2) mousex = mousewindow_x2;
  1378.              if (mousex<mousewindow_x1) mousex = mousewindow_x1;
  1379.              if (mousey>mousewindow_y2) mousey = mousewindow_y2;
  1380.              if (mousey<mousewindow_y1) mousey = mousewindow_y1;
  1381.              mousemoved = 1; // this is the program's indicator that it moved
  1382.              mousecnt++;   // must be a 3-button mouse then
  1383.              }
  1384.         break;
  1385.         }
  1386.    case 3: {
  1387.         byte4=inportb(mouseport);  // this byte's information is not known
  1388.         mousecnt++;
  1389.         break;
  1390.         }
  1391.    case 4: {
  1392.         byte5=inportb(mouseport);  // this byte's information is not known
  1393.         mousecnt=0;
  1394.            break;
  1395.         }
  1396.    }
  1397.  outportb(0x20,0x20);
  1398. }
  1399.  
  1400. void mousecursor_on(void)
  1401. {
  1402.  omousex=mousex;
  1403.  omousey=mousey;
  1404.  xorimage(omousex,omousey,mousecursor);
  1405.  cursor_on = 1;
  1406. }
  1407.  
  1408. void mousecursor_off(void)
  1409. {
  1410.  xorimage(omousex,omousey,mousecursor);
  1411.  cursor_on = 0;
  1412. }
  1413.  
  1414. void set_mousecursor(char *picture)
  1415. {
  1416.  mousecursor = picture;
  1417. }
  1418.  
  1419. void set_mousewindow(int x1,int y1,int x2,int y2)
  1420. {
  1421.  mousewindow_x1 = x1;
  1422.  mousewindow_x2 = x2;
  1423.  mousewindow_y1 = y1;
  1424.  mousewindow_y2 = y2;
  1425. }
  1426.  
  1427. void set_mousespeed(int breakover)
  1428. { // breakover in the range [0..127].  When X or Y on mouse exceeds
  1429.   // mousespeed, it doubles the value so it moves twice as fast.
  1430.   // recommended to be set to 80 for 2-button, somewhere near 25 for 3-button
  1431.   // I do this because I don't like the action of the 3-button mouse.  Too
  1432.   // slow to cover a whole screen.  Not so important for 2-button.
  1433.   // Double speed can be disabled by making it [128..255].
  1434.  mousespeed = breakover;
  1435. }
  1436.  
  1437. void interrupt testhandler1(...)
  1438. {
  1439.  switch (mousetest) {
  1440.    case 0: {
  1441.         byte1=inportb(0x2F8);
  1442.         mousebuttons = 2;
  1443.         if ((byte1 & 248)==128) mousebuttons++;
  1444.         }
  1445.   default: {
  1446.         mousetest++;
  1447.         byte1=inportb(0x2F8);
  1448.         }
  1449.   }
  1450.  if ((mousetest==mousebuttons==2) || (mousetest==4)) {
  1451.     mousetest=0x0B;  // set the interrupt number of the mouse in use
  1452.     mouseport=0x2F8;
  1453.     }
  1454.  outportb(0x20,0x20); // acknowledge int to hardware
  1455. }
  1456.  
  1457. void interrupt testhandler2(...)
  1458. {
  1459.  switch (mousetest) {
  1460.    case 0: {
  1461.         byte1=inportb(0x3F8);
  1462.         mousebuttons = 2;
  1463.         if ((byte1 & 248)==128) mousebuttons++;
  1464.         }
  1465.   default: {
  1466.         mousetest++;
  1467.         byte1=inportb(0x3F8);
  1468.         }
  1469.   }
  1470.  if ((mousetest==mousebuttons==2) || (mousetest==4)) {
  1471.     mousetest=0x0C;  // set the interrupt number of the mouse in use
  1472.     mouseport=0x3F8;
  1473.     }
  1474.  outportb(0x20,0x20); // acknowledge int to hardware
  1475. }
  1476.  
  1477. void interrupt testhandler3(...)
  1478. {
  1479.  switch (mousetest) {
  1480.    case 0: {
  1481.         byte1=inportb(0x3E8);
  1482.         mousebuttons = 2;
  1483.         if ((byte1 & 248)==128) mousebuttons++;
  1484.         }
  1485.   default: {
  1486.         mousetest++;
  1487.         byte1=inportb(0x3E8);
  1488.         }
  1489.   }
  1490.  if ((mousetest==mousebuttons==2) || (mousetest==4)) {
  1491.     mousetest=0x0A;  // set the interrupt number of the mouse in use
  1492.     mouseport=0x3E8;
  1493.     }
  1494.  outportb(0x20,0x20); // acknowledge int to hardware
  1495. }
  1496.  
  1497. int setupmouse(void)
  1498. {
  1499.  asm {
  1500.      mov ax,0
  1501.      int 0x33   // init mouse driver
  1502.      mov word ptr mousetest,ax
  1503.      }
  1504.  if (mousetest!=0xFFFF) {
  1505.     settextmode();
  1506.     printf("Mouse driver not installed!\n");
  1507.     return(0);
  1508.     }
  1509.  mousetest = 0;
  1510.  mouseport = 0;
  1511.  oldmousehandler1 = getvect(0x0B);    // com2
  1512.  setvect(0x0B,testhandler1);
  1513.  oldmousehandler2 = getvect(0x0C);    // com1
  1514.  setvect(0x0C,testhandler2);
  1515.  oldmousehandler3 = getvect(0x0A);    // com3
  1516.  setvect(0x0A,testhandler3);
  1517.  while (kbhit()) getch();
  1518.  while ((!kbhit()) && (mousetest<=10));
  1519.  setvect(0x0B,oldmousehandler1);
  1520.  setvect(0x0C,oldmousehandler2);
  1521.  setvect(0x0A,oldmousehandler3);
  1522.  if (kbhit()) {
  1523.     getch();
  1524.     settextmode();
  1525.     printf("Mouse detection aborted.\n");
  1526.     return(0);
  1527.     }
  1528.  else {
  1529.       cursor_on = 0;
  1530.       set_mousewindow(0,0,600,440);
  1531.       if (mousebuttons==2) set_mousespeed(80);
  1532.          else set_mousespeed(25);
  1533.       mousex = 320;
  1534.       mousey = 240;
  1535.       oldmousehandler1 = getvect(mousetest);
  1536.       atexit(closemouse);  // guarantee that the driver is closed on exit
  1537.       setvect(mousetest,mousehandler);
  1538.       return(1);          // set it back into graphics mode
  1539.       }
  1540. }
  1541.  
  1542. void updatecursor(void)
  1543. {
  1544.  if (mousemoved && cursor_on) {
  1545.     waitretrace();
  1546.     xorimage(omousex,omousey,mousecursor);
  1547.     omousex = mousex;
  1548.     omousey = mousey;
  1549.     mousemoved = 0;
  1550.     xorimage(omousex,omousey,mousecursor);
  1551.     }
  1552. }
  1553.  
  1554. void closemouse(void)
  1555. {
  1556.  if (mousetest!=0) setvect(mousetest,oldmousehandler1);
  1557.  mousetest = 0;
  1558. }
  1559.  
  1560. void shadebox(int sx,int sy)
  1561. {
  1562.  int vp,vp2;
  1563.  unsigned char far *start;
  1564.  
  1565.  for (vp2=sy; vp2<sy+50; vp2++) {
  1566.      start = putpixel(sx,vp2,getpixel(sx,vp2));
  1567.      for (vp=50; vp>0; vp--)
  1568.          *(start++) = 3+(*start);
  1569.      }
  1570. }
  1571.  
  1572. int sb_reset(void)
  1573. {
  1574. asm {
  1575.     MOV    DX,SBInt
  1576.     ADD    DL,6
  1577.     MOV    AL,1
  1578.     OUT    DX,AL
  1579.     IN     AL,DX
  1580.     }
  1581. RDSP05:
  1582. asm {
  1583.     INC    AL
  1584.     JNZ    RDSP05
  1585.     OUT    DX,AL
  1586.     MOV    CL,0x20
  1587.     }
  1588. RDSP10:
  1589.     sb_read();  // return value in al
  1590. asm {
  1591.     CMP    AL,0xAA
  1592.     JE     RDSP20
  1593.     LOOP   RDSP10
  1594.     XOR    AX,AX
  1595.     pop ds
  1596.     pop bp
  1597.     RET                      // return with ax=0 if could not reset
  1598.     }
  1599. RDSP20:
  1600. asm {
  1601.     MOV    AX,1
  1602.     pop ds
  1603.     pop bp
  1604.     RET                      // return with ax=1 for no error
  1605.     }
  1606. return(0);  // dummy code
  1607. }
  1608.  
  1609. int sb_read(void)
  1610. {
  1611. asm {
  1612.     push cx
  1613.     push dx
  1614.     MOV    DX,SBInt
  1615.     ADD    DL,0x0E
  1616.     MOV    CX,0xFF
  1617.     }
  1618. RDT10:
  1619. asm {
  1620.     IN     AL,DX
  1621.     OR     AL,AL
  1622.     JS     RDT20
  1623.     LOOP   RDT10
  1624.     }
  1625. RDT20:
  1626. asm {
  1627.     SUB    DL,4
  1628.     IN     AL,DX
  1629.     pop dx
  1630.     pop cx
  1631.     pop ds
  1632.     pop bp
  1633.     RET
  1634.     }
  1635. return(0);  // dummy code
  1636. }
  1637.  
  1638. void sb_write(char letr)
  1639. {
  1640. asm {
  1641.     push cx
  1642.     push dx
  1643.     MOV    DX,SBInt
  1644.     ADD    DX,0x0C
  1645.     MOV    CX,0xFF
  1646.     }
  1647. WD10:
  1648. asm {
  1649.     IN     AL,DX
  1650.     OR     AL,AL
  1651.     JNS    WD20
  1652.     LOOP   WD10
  1653.     }
  1654. WD20:
  1655. asm {
  1656.     MOV    AL,letr
  1657.     OUT    DX,AL
  1658.     pop dx
  1659.     pop cx
  1660.     pop ds
  1661.     pop bp
  1662.     RET
  1663.     }
  1664. }
  1665.  
  1666. void closedma(void)
  1667. {
  1668.  if (SBDMA) {
  1669.     setvect(SBDMA+8,oldsbhandler1);
  1670.     asm {
  1671.         cli
  1672.         mov al,oldint21
  1673.         out 0x21,al                    // reset IRQ masks
  1674.         sti
  1675.         }
  1676.     sb_reset();                        // for good measure
  1677.     }
  1678.  SBDMA = 0;
  1679. }
  1680.  
  1681. void interrupt sbhandler(...)
  1682. {
  1683.  inportb(SBInt+0x0E);
  1684.  sbplaying=0;
  1685.  if (currentbuffer!=nextbuffer) {
  1686.     currentbuffer=nextbuffer;
  1687.     initdma(buffer[currentbuffer],bufflen[currentbuffer],rate[currentbuffer]);
  1688.     }
  1689.  outportb(0x20,0x20);
  1690. }
  1691.  
  1692. int sb_detect(void)
  1693. {
  1694.  long loop;
  1695.  
  1696.  do {
  1697.     SBInt+=0x10;
  1698.     } while ((SBInt<0x270) && (!sb_reset()));
  1699.  sb_write(0xD1);                                // this turns on the speaker
  1700.  if (!sb_reset()) return(0);
  1701. //=============This next part detects the IRQ that is called by DMA complete=
  1702.  SBDMA=0;
  1703.  oldsbhandler1 = getvect(0x0A);
  1704.  setvect(0x0A,sbtesthandler1);
  1705.  oldsbhandler2 = getvect(0x0B);
  1706.  setvect(0x0B,sbtesthandler2);
  1707.  oldsbhandler3 = getvect(0x0D);
  1708.  setvect(0x0D,sbtesthandler3);
  1709.  oldsbhandler4 = getvect(0x0F);
  1710.  setvect(0x0F,sbtesthandler4);
  1711.  asm {
  1712.      cli
  1713.      in  al,0x21
  1714.      mov oldint21,al
  1715.      and al,83        // mask on for IRQ 2,3,5,7
  1716.      out 0x21,al
  1717.      sti
  1718.      }
  1719.  sb_write(0xF2);                        // request DMA Interrupt from SB
  1720.  loop=1000;
  1721.  while ((loop>0) && !SBDMA && !kbhit()) // wait for keypress or IRQ
  1722.        loop--;
  1723.  setvect(0x0A,oldsbhandler1);
  1724.  setvect(0x0B,oldsbhandler2);
  1725.  setvect(0x0D,oldsbhandler3);
  1726.  setvect(0x0F,oldsbhandler4);
  1727.  asm {
  1728.      cli
  1729.      mov al,oldint21
  1730.      out 0x21,al     // return all to previous setting
  1731.      sti
  1732.      }
  1733.  if (SBDMA) {
  1734.     oldsbhandler1 = getvect(SBDMA+8);
  1735.     atexit(closedma);  // guarantee that the IRQ is closed on exit
  1736.     setvect(SBDMA+8,sbhandler);
  1737.     asm {
  1738.         cli
  1739.         mov ah,1
  1740.         mov al,oldint21
  1741.         mov cx,word ptr SBDMA
  1742.         shl ah,cl
  1743.         not ah
  1744.         and al,ah        // mask on for specific IRQ
  1745.         out 0x21,al
  1746.         sti
  1747.         }
  1748.     return(1);          // set it back into graphics mode
  1749.     }
  1750.     else return(0);
  1751. }
  1752.  
  1753. void interrupt sbtesthandler1(...)
  1754. {
  1755.  inportb(0x0E+SBInt);      // dispose of byte, signal to SB that IRQ received
  1756.  SBDMA=2;
  1757.  outportb(0x20,0x20); // acknowledge int to hardware
  1758. }
  1759.  
  1760. void interrupt sbtesthandler2(...)
  1761. {
  1762.  inportb(0x0E+SBInt);      // dispose of byte, signal to SB that IRQ received
  1763.  SBDMA=3;
  1764.  outportb(0x20,0x20); // acknowledge int to hardware
  1765. }
  1766.  
  1767. void interrupt sbtesthandler3(...)
  1768. {
  1769.  inportb(0x0E+SBInt);      // dispose of byte, signal to SB that IRQ received
  1770.  SBDMA=5;
  1771.  outportb(0x20,0x20); // acknowledge int to hardware
  1772. }
  1773.  
  1774. void interrupt sbtesthandler4(...)
  1775. {
  1776.  inportb(0x0E+SBInt);      // dispose of byte, signal to SB that IRQ received
  1777.  SBDMA=7;
  1778.  outportb(0x20,0x20); // acknowledge int to hardware
  1779. }
  1780.  
  1781. void initdma(char far *buffer,int length,int rate)
  1782. {
  1783.  long address;
  1784.  
  1785.  address=((((unsigned long) buffer)>>16)<<4)+(((unsigned long) buffer) & 0xFFFF);
  1786.  asm cli
  1787.  outportb(0x0A,4+DMAChannel);
  1788.  outportb(0x0C,0);
  1789.  outportb(0x0B,0x48+DMAChannel);
  1790.  outportb(DMAChannel<<1,address & 255);       // low byte
  1791.  outportb(DMAChannel<<1,(address>>8) & 255);  // high byte
  1792.  outportb(Page[DMAChannel],address>>16);      // 64k page selector
  1793.  outportb((DMAChannel<<1)+1,(length-1) & 255);// (buffer length-1) & 255
  1794.  outportb((DMAChannel<<1)+1,(length-1)>>8);   // (buffer length >> 8)
  1795.  outportb(0x0A,DMAChannel);                   // DMA is ready
  1796.  
  1797.  sb_write(0x40);
  1798.  sb_write(256-1000000L/rate);
  1799.  sb_write(0x14);                     // DMA type (0x14 is 8bit up to 23k/s)
  1800.  sb_write((length-1) & 255);
  1801.  sb_write((length-1) >> 8);          // write length of sample
  1802.  asm sti
  1803.  sbplaying=1;                        // while nonzero, DMA is still playing
  1804. }
  1805.  
  1806. void playdma(char *fname,int playrate)
  1807. {
  1808.  long address;
  1809.  FILE *f;
  1810.  
  1811.  dmabuf=(char *)farmalloc(24576);
  1812.                 // This is for two 8k buffers.  Idea is that it
  1813.                 // has to cross an 8k boundary if you allocate >8k
  1814.                 // so we guarantee to cross a page boundary twice
  1815.                 // and yield two DMA buffers 8k each.
  1816.  address = ((((unsigned long) dmabuf) >> 16) << 4)+(((unsigned long) dmabuf) & 0xFFFF);
  1817.  buffer[0]=dmabuf+8192-(address & 8191);   // buffer is 8k and starts on
  1818.  buffer[1]=dmabuf+16384-(address & 8191);  // even 8k boundary
  1819.  
  1820.  if (NULL==(f=fopen(fname,"rb"))) {
  1821.     settextmode();
  1822.     printf("File %s not found in current directory.\n",fname);
  1823.     exit(1);
  1824.     }
  1825.  currentbuffer=0;
  1826.  nextbuffer=0;
  1827.  bufflen[currentbuffer]=fread(buffer[0],1,8192,f);
  1828.  rate[currentbuffer]=playrate;  // each 8k buffer has its own rate, in case
  1829.  rate[1]=playrate;  // you want to do mixing or change files without pops...?
  1830.  initdma(buffer[currentbuffer],bufflen[currentbuffer],rate[currentbuffer]);
  1831.  while ((bufflen[currentbuffer]==8192) && !kbhit()) {
  1832.        nextbuffer=currentbuffer ^ 1;  // flip between 0 and 1
  1833.        bufflen[nextbuffer]=fread(buffer[nextbuffer],1,8192,f);
  1834.        while (currentbuffer!=nextbuffer);  // wait for IRQ to pop
  1835.               // could be doing something cool instead of waiting, but that's
  1836.               // not the point of this routine.  this is just a sample.
  1837.        }
  1838.  fclose(f);
  1839.  if (currentbuffer!=nextbuffer)
  1840.     nextbuffer=currentbuffer; // skip next buffer if it was aborted
  1841.  sb_write(0xD0);  // stop DMA +now+
  1842.  while (kbhit()) getch();
  1843.  farfree(dmabuf);
  1844. }
  1845.  
  1846. void doshadebobs()
  1847. {
  1848.  int mx,my,loop,loop2,count;
  1849.  
  1850.  mx=0;
  1851.  my=0;
  1852.  loop=320;
  1853.  loop2=240;
  1854.  count=0;
  1855.  while (!kbhit() && count<1250) {
  1856.        mx+=random(3)-1;
  1857.        my+=random(3)-1;
  1858.        if (mx>3) mx=3;
  1859.        if (mx<-3) mx=-3;
  1860.        if (my>3) my=3;
  1861.        if (my<-3) my=-3;
  1862.        loop+=mx;
  1863.        loop2+=my;
  1864.        if (loop>970) loop-=970;
  1865.        if (loop<0) loop+=970;
  1866.        if (loop2>totalram-50) loop2-=totalram-50;
  1867.        if (loop2<0) loop2+=totalram-50;
  1868.        shadebox(loop,loop2);
  1869.        count++;
  1870.        }
  1871.  while (kbhit()) getch();
  1872. }
  1873.  
  1874. void dooddbobs()
  1875. {
  1876.  int vx,vy,mx,my,loop,loop2,count;
  1877.  char *weirdbox;
  1878.  
  1879.  weirdbox = (unsigned char *) malloc(2504);
  1880.  if (weirdbox==NULL) {
  1881.     settextmode();
  1882.     printf("Memory allocation error.  Tried to allocate 2500 bytes.\n");
  1883.     printf("Max available memory is %lu.\n",(unsigned long) coreleft());
  1884.     printf("Max available far memory is %lu.\n",(unsigned long) farcoreleft());
  1885.     exit(1);
  1886.     }
  1887.  memset(weirdbox,0,2504);
  1888.  weirdbox[0] = 50;
  1889.  weirdbox[2] = 50;
  1890.  for (mx=0; mx<50; mx++) {
  1891.      weirdbox[mx+4]=63;
  1892.      weirdbox[mx*50+4]=63;
  1893.      }
  1894.  mx=0;
  1895.  my=0;
  1896.  vx=0;
  1897.  vy=0;
  1898.  loop=320;
  1899.  loop2=240;
  1900.  count=0;
  1901.  while (!kbhit() && count<750) {
  1902.        mx+=random(3)-1;
  1903.        my+=random(3)-1;
  1904.        if (mx>5) mx=5;
  1905.        if (mx<-5) mx=-5;
  1906.        if (my>5) my=5;
  1907.        if (my<-5) my=-5;
  1908.        loop+=mx;
  1909.        loop2+=my;
  1910.        if (loop>970) {
  1911.           loop=970;
  1912.           mx=-mx;
  1913.           }
  1914.        if (loop<0) {
  1915.           loop=0;
  1916.           mx=-mx;
  1917.           }
  1918.        if (loop2>totalram-55) {
  1919.           loop2=totalram-55;
  1920.           my=-my;
  1921.           }
  1922.        if (loop2<0) {
  1923.           loop2=0;
  1924.           my=-my;
  1925.           }
  1926.        vx=loop-320;
  1927.        vy=loop2-240;
  1928.        if (vx<0) vx+=1024;
  1929.        if (vy<0) vy+=totalram;
  1930.        setvisualstart(vx,vy);
  1931.        putimage(loop,loop2,weirdbox);
  1932.        delay(10);
  1933.        count++;
  1934.        }
  1935.  setvisualstart(0,0);
  1936.  while (kbhit()) getch();
  1937.  free(weirdbox);
  1938. }
  1939.  
  1940. void domove()
  1941. {
  1942.  int mx,my,loop,loop2,count;
  1943.  
  1944.  mx=0;
  1945.  my=0;
  1946.  loop=0;
  1947.  loop2=0;
  1948.  count=0;
  1949.  while (!kbhit() && count<750) {
  1950.        mx+=random(3)-1;
  1951.        my+=random(3)-1;
  1952.        if (mx>6) mx=6;
  1953.        if (mx<-6) mx=-6;
  1954.        if (my>6) my=6;
  1955.        if (my<-6) my=-6;
  1956.        loop+=mx;
  1957.        loop2+=my;
  1958.        if (loop>1024) loop-=1024;
  1959.        if (loop<0) loop+=1024;
  1960.        if (loop2>totalram) loop2-=totalram;
  1961.        if (loop2<0) loop2+=totalram;
  1962.        setvisualstart(loop,loop2);
  1963.        delay(10);
  1964.        count++;
  1965.        }
  1966.  setvisualstart(0,0);
  1967.  while (kbhit()) getch();
  1968. }
  1969.  
  1970. void dofire(void)
  1971. {
  1972.  int loop,temp,temp2,fires,counter,tick;
  1973.  unsigned char *flamearray;
  1974.  
  1975.  flamearray = (unsigned char *) malloc(firewidth*fireheight+5);
  1976.  if (flamearray==NULL) {
  1977.     settextmode();
  1978.     printf("Memory allocation error.  Tried to allocate 16k bytes.\n");
  1979.     printf("Max available memory is %lu.\n",(unsigned long) coreleft());
  1980.     printf("Max available far memory is %lu.\n",(unsigned long) farcoreleft());
  1981.     exit(1);
  1982.     }
  1983.  for (loop=0; loop<64; loop++)
  1984.      setcolor(loop,0,0,loop);
  1985.  for (; loop<128; loop++)
  1986.      setcolor(63,loop & 63,0,loop);
  1987.  for (; loop<256; loop++)
  1988.      setcolor(63,63,loop & 63,loop);
  1989.  for (loop=0; loop<32; loop++)
  1990.      setcolor(loop+loop,loop+loop,loop+loop,loop+256);
  1991.  for (; loop<64; loop++)
  1992.      setcolor(63-loop-loop,63-loop-loop,63,loop+256);
  1993.  for (; loop<128; loop++)
  1994.      setcolor(0,loop & 63,63,loop+256);
  1995.  for (; loop<256; loop++)
  1996.      setcolor(loop & 63,63,63,loop+256);
  1997.  setpalette(pal);
  1998.  memset(flamearray,0,firewidth*fireheight+5);
  1999.  flamearray[0]=firewidth & 255;
  2000.  flamearray[1]=firewidth >> 8;
  2001.  // note that to remove the ugly bottom line, change the following lines to
  2002.  // contain "(fireheight-1)" instead of fireheight.  This just makes it
  2003.  // invisible, although it is used for calculation purposes.  I left it
  2004.  // in for instructional purposes.  <shrug>
  2005.  flamearray[2]=fireheight & 255;  // set up array to be put as putimage
  2006.  flamearray[3]=fireheight >> 8;
  2007.  fires=25;
  2008.  counter=0;
  2009.  tick=0;
  2010.  while (!kbhit() && tick<2) {
  2011.        if (counter==300) setpalette(pal+768);
  2012.           else if (counter==600) {
  2013.                setpalette(pal);
  2014.                counter=0;
  2015.                tick++;
  2016.                }
  2017.        for (loop=0; loop<fires; loop++)
  2018.            flamearray[random(firewidth)/2+firewidth/4+firewidth*(fireheight-1)+4]=random(256);
  2019.        for (temp2=firewidth+4; temp2<firewidth*(fireheight-1)+4; temp2++) {
  2020.            temp=(((int)flamearray[temp2+firewidth]+(int)flamearray[temp2+1]+
  2021.                   (int)flamearray[temp2-1]+(int)flamearray[temp2]) >> 2)-2;
  2022.            if (temp>0) flamearray[temp2-firewidth]=temp;
  2023.               else flamearray[temp2-firewidth]=0;
  2024.            }
  2025.        for (loop=(fireheight-1)*firewidth+4; loop<fireheight*firewidth+4; loop++)
  2026.            if (flamearray[loop]>1) {
  2027.               flamearray[loop]-=2;
  2028.               flamearray[loop-firewidth]=flamearray[loop];
  2029.               }
  2030.        for (loop=firewidth*(fireheight-1)+4; loop<firewidth*fireheight+4; loop++)
  2031.            if (random(2)==0) flamearray[loop]=(flamearray[loop]+flamearray[loop+1])>>1;
  2032.               else flamearray[loop]=(flamearray[loop]+flamearray[loop-1])>>1;
  2033.        putimage(0,480-fireheight,flamearray);
  2034.        counter++;
  2035.        }
  2036.  while (kbhit()) getch();
  2037.  free(flamearray);
  2038. }
  2039.  
  2040. void domouse(void)
  2041. {
  2042.  int mx;
  2043.  char *cursorpic;
  2044.  
  2045.  settextmode();
  2046.  printf("Please pet your mouse. (or press a key if you don't have one).\n");
  2047.  if (!setupmouse()) exit(1);
  2048.  printf("\n\n Two and Three button mice work with this demo and source code.\n");
  2049.  printf("The center button is simulated by pressing left and right on a 2-button.\n");
  2050.  printf("This does NOT work for three button mice.  Use the actual center button.\n\n");
  2051.  printf("  Found %d-button mouse at IRQ %x, Port %x. \n",mousebuttons,mousetest,mouseport);
  2052.  printf("\n\n\n    To begin the test, press a button.  To exit, press center button.");
  2053.  while (!mouseb2 && !mouseb1);
  2054.  if (!InitVesa()) exit(1);
  2055.  for (mx=0; mx<64; mx++) {
  2056.      setcolor(0,mx,mx,mx);
  2057.      setcolor(mx,63,63-mx,mx+63);
  2058.      setcolor(63,63-mx,0,mx+127);
  2059.      setcolor(63-mx,0,0,mx+191);
  2060.      setcolor(0,mx,mx,mx+255);
  2061.      setcolor(mx,63,63-mx,mx+63+256);
  2062.      setcolor(63,63-mx,0,mx+127+256);
  2063.      setcolor(63-mx,0,0,mx+191+256);
  2064.      }
  2065.  setpalette(pal);
  2066.  cursorpic=(unsigned char *) malloc(2504);
  2067.  if (cursorpic==NULL) {
  2068.     settextmode();
  2069.     printf("Memory allocation error.  Tried to allocate 2500 bytes.\n");
  2070.     printf("Max available memory is %lu.\n",(unsigned long) coreleft());
  2071.     printf("Max available far memory is %lu.\n",(unsigned long) farcoreleft());
  2072.     exit(1);
  2073.     }
  2074.  memset(cursorpic,0,2504);
  2075.  cursorpic[0] = 50;
  2076.  cursorpic[2] = 50;
  2077.  for (mx=0; mx<50; mx++) {
  2078.      cursorpic[mx+4]=63;
  2079.      cursorpic[mx*50+4]=63;
  2080.      cursorpic[mx+2454]=63;
  2081.      cursorpic[mx*50+53]=63;
  2082.      }
  2083.  set_mousecursor(cursorpic);
  2084.  set_mousewindow(0,0,590,430);
  2085.  mousecursor_on();
  2086.  while (!kbhit() && !mouseb3) {
  2087.        updatecursor();
  2088.        if (mouseb1) putpixel(random(640),random(480),63);
  2089.        if (mouseb2) putpixel(random(640),random(480),random(256));
  2090.        }
  2091.  while (kbhit()) getch();
  2092.  mousecursor_off();
  2093.  free(cursorpic);
  2094. }
  2095.  
  2096. void main(void)
  2097. {
  2098.  int loop,loop2,loop3;
  2099.  
  2100.  if (!Check386()) {
  2101.     printf("An 80386 or higher machine is required to execute this program.\n");
  2102.     exit(1);
  2103.     }
  2104.  while (loop2!=(loop=Checktimer()))
  2105.        loop2=loop;
  2106.  printf("Speed judged at %x...Press a key to start. (Everything else is automatic)\n",loop);
  2107.  getch();
  2108.  fadeoutpalette(20000);
  2109.  randomize();
  2110.  if (InitVesa()) {
  2111.     for (loop=0; loop<64; loop++) {
  2112.         setcolor(0,loop,loop,loop);
  2113.         setcolor(loop,63,63-loop,loop+63);
  2114.         setcolor(63,63-loop,0,loop+127);
  2115.         setcolor(63-loop,0,0,loop+191);
  2116.         setcolor(0,loop,loop,loop+255);
  2117.         setcolor(loop,63,63-loop,loop+63+256);
  2118.         setcolor(63,63-loop,0,loop+127+256);
  2119.         setcolor(63-loop,0,0,loop+191+256);
  2120.         }
  2121.     for (loop2=0; loop2<1024; loop2++)
  2122.         for (loop=0; loop<1024; loop++)
  2123.             putpixel(loop,loop2,loop+loop2);
  2124.     fadeinpalette(pal,20000);
  2125.     doshadebobs();
  2126.     for (loop=0; loop<1024; loop+=16)
  2127.         for (loop2=0; loop2<1024; loop2+=16)
  2128.             clrimage(loop2,loop,15,15);
  2129.     dooddbobs();
  2130.     domove();
  2131.     fadeoutpalette(64000);
  2132.     clearscr();
  2133.     if (sb_detect())
  2134.        playdma("vesanoiz.wav",22050);
  2135.     dofire();
  2136.     domouse();
  2137.     settextmode();
  2138.     }
  2139.  else printf("InitVesa() call failed.\n");
  2140. }
  2141.